package main

import (
	"context"
	"embed"
	"encoding/json"
	"errors"
	"flag"
	"html/template"
	"log"
	"mime"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
)

//go:embed templates/*
var templateFS embed.FS

//go:embed static/*
var staticFS embed.FS

// 添加自定义 MIME 类型
func init() {
	err := mime.AddExtensionType(".mkv", "video/x-matroska")
	if err != nil {
		log.Println("无法添加 MKV MIME 类型:", err)
	}
}

var (
	port = flag.String("port", "8080", "Server port")
	path = flag.String("path", ".", "Directory path to video files")
)

type Server struct {
	rootPath     string
	tvController *TVController
	currentMedia string // 当前投屏的视频路径
}

func (s *Server) homeHandler(w http.ResponseWriter, r *http.Request) {
	devices, err := s.tvController.GetDevices()

	// 即使设备发现失败，也继续获取视频列表
	deviceMap := make(map[string]string)
	if err == nil {
		for _, device := range devices {
			deviceMap[device.Model] = device.URL
		}
	}

	videos, err := listVideos(s.rootPath)
	if err != nil {
		http.Error(w, "Failed to list videos", http.StatusInternalServerError)
		return
	}

	tmpl := template.Must(template.ParseFS(templateFS, "templates/home.html"))
	tmpl.Execute(w, struct {
		Devices map[string]string
		Videos  []string
	}{
		Devices: deviceMap,
		Videos:  videos,
	})
}

func (s *Server) playHandler(w http.ResponseWriter, r *http.Request) {
	if s.tvController == nil || s.currentMedia == "" {
		http.Error(w, "No active casting session", http.StatusBadRequest)
		return
	}

	devices, err := s.tvController.GetDevices()
	if err != nil {
		http.Error(w, "Failed to load devices", http.StatusInternalServerError)
		return
	}

	deviceName := "Unknown Device"
	for _, device := range devices {
		if device.URL == s.tvController.dmrURL {
			deviceName = device.Model
			break
		}
	}

	videoName := filepath.Base(s.currentMedia)

	tmpl := template.Must(template.ParseFS(templateFS, "templates/play.html"))
	tmpl.Execute(w, struct {
		Device string
		Video  string
	}{
		Device: deviceName,
		Video:  videoName,
	})
}

func (s *Server) stopHandler(w http.ResponseWriter, r *http.Request) {
	if s.tvController == nil || s.currentMedia == "" {
		http.Error(w, "No active casting session", http.StatusBadRequest)
		return
	}

	// 发送停止命令
	err := s.tvController.StopCast()
	if err != nil {
		http.Error(w, "Failed to stop casting", http.StatusInternalServerError)
		return
	}

	// 清除状态
	s.currentMedia = ""

	// 跳转回首页
	http.Redirect(w, r, "/", http.StatusFound)
}

func (s *Server) castHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
		return
	}

	dmr := r.FormValue("dmr")
	video := r.FormValue("video")
	log.Println("cast ", video)

	if dmr == "" || video == "" {
		http.Error(w, "Missing device or video", http.StatusBadRequest)
		return
	}

	// 使用新方法检查投屏状态
	if s.tvController.IsCasting() {
		log.Println("Existing cast detected, stopping first")
		if err := s.tvController.StopCast(); err != nil {
			http.Error(w, "Failed to stop existing cast: "+err.Error(), http.StatusInternalServerError)
			return
		}
		s.currentMedia = "" // 清除旧状态
	}

	// 设置设备并投屏
	if err := s.tvController.SetDevice(dmr); err != nil {
		http.Error(w, "Invalid device URL", http.StatusBadRequest)
		return
	}

	if err := s.tvController.CastVideo(video); err != nil {
		http.Error(w, "Failed to cast video", http.StatusInternalServerError)
		return
	}

	// 保存当前投屏状态
	s.currentMedia = video

	// 跳转至播放页面
	http.Redirect(w, r, "/play", http.StatusFound)
}

func (s *Server) refreshHandler(w http.ResponseWriter, r *http.Request) {
	devices, err := s.tvController.GetDevices()
	if err != nil {
		http.Error(w, "Failed to refresh devices", http.StatusInternalServerError)
		return
	}

	deviceMap := make(map[string]string)
	for _, device := range devices {
		deviceMap[device.Model] = device.URL
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(deviceMap)
}

func (s *Server) videoHandler(w http.ResponseWriter, r *http.Request) {
	file := r.URL.Query().Get("file")
	if file == "" {
		http.Error(w, "Missing file parameter", http.StatusBadRequest)
		return
	}

	if strings.HasSuffix(file, ".mkv") {
		// 转码 MKV 为 MP4 流式输出
		cmd := exec.Command("ffmpeg",
			"-i", file,
			"-f", "mp4",
			"-vcodec", "libx264",
			"-acodec", "aac",
			"-movflags", "frag_keyframe+empty_moov",
			"pipe:1")

		w.Header().Set("Content-Type", "video/mp4")
		cmd.Stdout = w
		cmd.Stderr = os.Stderr

		err := cmd.Run()
		if err != nil {
			log.Printf("FFmpeg 转码错误: %v", err)
			http.Error(w, "视频转码失败", http.StatusInternalServerError)
		}
	} else {
		// 直接播放其他格式（如 MP4）
		http.ServeFile(w, r, file)
	}

	// http.ServeFile(w, r, file)
}

func listVideos(root string) ([]string, error) {
	var videos []string
	err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() && isVideoFile(path) {
			videos = append(videos, path)
		}
		return nil
	})
	return videos, err
}

func isVideoFile(path string) bool {
	ext := strings.ToLower(filepath.Ext(path))
	return ext == ".mp4" || ext == ".mkv" || ext == ".avi" || ext == ".mov"
}

func main() {
	flag.Parse()

	server := &Server{
		rootPath:     *path,
		tvController: NewTVController(),
	}

	mux := http.NewServeMux()
	mux.HandleFunc("/", server.homeHandler)
	mux.HandleFunc("/cast", server.castHandler)
	mux.HandleFunc("/play", server.playHandler)
	mux.HandleFunc("/stop", server.stopHandler)
	mux.HandleFunc("/refresh-devices", server.refreshHandler)
	mux.HandleFunc("/video", server.videoHandler)
	mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFS))))

	srv := &http.Server{
		Addr:    ":" + *port,
		Handler: mux,
	}

	// Graceful shutdown
	ctx, stop := context.WithCancel(context.Background())
	defer stop()

	go func() {
		log.Printf("Starting server on http://localhost:%s", *port)
		if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			log.Fatalf("Failed to start server: %v", err)
		}
	}()

	// 监听中断信号，触发上下文取消
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-quit
		log.Println("Shutting down server...")
		if err := srv.Shutdown(context.Background()); err != nil {
			log.Fatalf("Server forced to shutdown: %v", err)
		}
		stop()
	}()

	<-ctx.Done()

	log.Println("Shutting down server...")
	if err := srv.Shutdown(context.Background()); err != nil {
		log.Fatalf("Server forced to shutdown: %v", err)
	}

	log.Println("Server exited gracefully.")
}
